#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include "server.h"
#include <bits/errno.h>
#include <unistd.h>
#include <syslog.h>

extern void error(const char* cause, const char* message);

/*
 * main.c
 *
 *  Created on: Jun 19, 2011
 *      Author: sainw
 */
#define SERVER_PORT 8888
#define REQUEST_QUE 10
#define STATIC_DIR "."

/* HTTP response, header, and body, indicating that we didn't
 understand the request. */
static char* bad_request_response = "HTTP/1.0 400 Bad Request\n"
	"Content-type: text/html\n"
	"\n"
	"<html>\n"
	" <body>\n"
	" <h1>Bad Request</h1>\n"
	" <p>This server did not understand your request.</p>\n"
	" </body>\n"
	"</html>\n";

/* HTTP response, header, and body template, indicating that the
 method was not understood. */
static char* bad_method_response_template =
		"HTTP/1.0 501 Method Not Implemented\n"
			"Content-type: text/html\n"
			"\n"
			"<html>\n"
			" <body>\n"
			" <h1>Method Not Implemented</h1>\n"
			" <p>The method %s is not implemented by this server.</p>\n"
			" </body>\n"
			"</html>\n";

/* HTTP response, header, and body template, indicating that the
 requested document was not found. */
static char* not_found_response_template = "HTTP/1.0 404 Not Found\n"
	"Content-type: text/html\n"
	"\n"
	"<html>\n"
	" <body>\n"
	" <h1>Not Found</h1>\n"
	" <p>The requested URL %s was not found on this server.</p>\n"
	" </body>\n"
	"</html>\n";

static char* ok_response = "HTTP/1.0 200 OK\n"
	"Content-type: text/html \n"
	"\n";

static void get_file(int connection_fd, char *file) {
	fprintf(stderr, "get_file: (%s) \n", file);
	FILE *fin, *fout;
	FILE* fp;
	int ch;

	fin = fopen(file, "r");
	if (fin == NULL) {
		fprintf(stderr, "Cannot open for reading\n");
		return (-1);
	}
	fp = fdopen(connection_fd, "w");
	if (fp == NULL) {
		fprintf(stderr, "Cannot open for writing\n");
		return (-1);
	}
	write(connection_fd, ok_response, strlen(ok_response));

	while ((ch = fgetc(fin)) != EOF)
		fputc(ch, fp);
	fclose(fp);
	fclose(fin);
	return (0);
}

static void handle_get(int connection_fd, const char* page) {
	struct server_module* module = NULL;
	char full_path[200];
	/* Make sure the requested page begins with a slash and does not
	 contain any additional slashes -- we don't support any
	 subdirectories. */
	if (*page == '/' && strchr(page + 1, '/') == NULL) {
		//		char module_file_name[64];
		//		/* The page name looks OK. Construct the module name by appending
		//		 ".so" to the page name. */
		//		snprintf(module_file_name, sizeof(module_file_name), "%s.so", page + 1);
		//		/* Try to open the module. */
		//		module = module_open(module_file_name);
	}
	fprintf(stderr, "%s: get_file: (%s) \n", program_name, page);
	full_path[0] = '\0';
	strcat(full_path, ".");
	strcat(full_path, page);
	fprintf(stderr, "full_path: (%s) \n", full_path);
	get_file(connection_fd, full_path);
	fprintf(stderr, "%s: end get_file: (%s) \n", program_name, page);
	close(connection_fd);
}

static void serve_request(int connection_fd) {

	char buffer[256];
	ssize_t bytes_read;

	bytes_read = read(connection_fd, buffer, sizeof(buffer) - 1);
	if (bytes_read > 0) {
		char method[sizeof(buffer)];
		char url[sizeof(buffer)];
		char protocol[sizeof(buffer)];

		/* Terminate with null to do string operation */
		buffer[bytes_read] = '\0';

		/* GET /index.html Http1.1 HTTP request*/sscanf(buffer, "%s %s %s",
				method, url, protocol);
		fprintf(stderr, "String: get buffer \n");
		/* The client may send various header information following the
		 request. For this HTTP implementation, we don't care about it.
		 However, we need to read any data the client tries to send. Keep
		 on reading data until we get to the end of the header, which is
		 delimited by a blank line. HTTP specifies CR/LF as the line
		 delimiter. */
		while (strstr(buffer, "\r\n\r\n") == NULL)
			bytes_read = read(connection_fd, buffer, sizeof(buffer));

		/* Make sure the last read didn't fail. If it did, there's a
		 problem with the connection, so give up. */
		if (bytes_read == -1) {
			close(connection_fd);
			return;
		}
		/* Check the protocol field. We understand HTTP versions 1.0 and
		 1.1. */
		if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1")) {
			fprintf(stderr, "protocol error\n");
			/* We don't understand this protocol. Report a bad response. */
			write(connection_fd, bad_request_response,
					sizeof(bad_request_response));
		} else if (strcmp(method, "GET")) {
			fprintf(stderr, "method error\n");
			/* This server only implements the GET method. The client
			 specified some other method, so report the failure. */
			char response[1024];
			snprintf(response, sizeof(response), bad_method_response_template,
					method);
			write(connection_fd, response, strlen(response));
		} else
			/* A valid request. Process it.*/
			fprintf(stderr, "handle get\n");
		handle_get(connection_fd, url);
		fprintf(stderr, "end handle get\n");
	} else if (bytes_read == 0)
		error("Read o byte", strerror(errno));
	else
		error("Read error", strerror(errno));
}

void start_server() {
	fprintf(stderr, "in server started\n");
	int server_socket;
	struct sockaddr_in socket_address;
	int rval;

	/*Create a socket*/
	server_socket = socket(PF_INET, SOCK_STREAM, 0);

	memset(&socket_address, 0, sizeof(socket_address));
	socket_address.sin_family = AF_INET;
	socket_address.sin_port = htons(SERVER_PORT);
	socket_address.sin_addr.s_addr = htonl(INADDR_ANY);

	/* Bind the socket to that address. */
	rval = bind(server_socket, &socket_address, sizeof(socket_address));

	rval = listen(server_socket, REQUEST_QUE);

	while (1) {
		struct sockaddr_in remote_address;
		socklen_t address_length;
		int connection;
		pid_t child_pid;

		/* Accept a connection. This call blocks until a connection is
		 ready. */
		address_length = sizeof(remote_address);
		connection = accept(server_socket, &remote_address, &address_length);
		if (connection == -1) {
			error("Connection error", strerror(errno));
		}

		/* Serve the request */
		fprintf(stderr, "server request\n");
		serve_request(connection);
		fprintf(stderr, "End server request\n");
	}
	close(server_socket);
}

int main(int argc, char *argv[]) {
	pid_t pid, sid;

	fprintf(stderr, "server started\n");
	program_name = argv[0];

	start_server();

//
//	pid = fork();
//	if (pid < 0) {
//		return -1;
//	}
//	if (pid > 0) {
//		/*Parent*/
//		return 0;
//	}
//
//	/* Change the file mode mask */
//	umask(0);
//
//	/* Create a new SID for the child process */
//	sid = setsid();
//	if (sid < 0) {
//		/* Log the failure */
//		return -1;
//	}
//
//	/* Change the current working directory */
//	if ((chdir("/")) < 0) {
//		/* Log the failure */
//		return -1;
//	}
//
//	/* Close out the standard file descriptors */
//	close(STDIN_FILENO);
//	close(STDOUT_FILENO);
//	close(STDERR_FILENO);
//
//	fprintf(stderr, "server ended\n");
	return 0;
}
